/*
 * Copyright 2012-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.web.server;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.util.Assert;

/**
 * {@link BeanPostProcessor} that applies all {@link ErrorPageRegistrar}s from the bean
 * factory to {@link ErrorPageRegistry} beans.
 * 当前类实现了BeanPostProcessor和BeanFactoryAware接口，在spring refresh()方法过程中的第6步的时候即执行registerBeanPostProcessors(beanFactory)方法时会获取容器中
 * 所有BeanPostProcessor接口的bd,然后进行bean对象的生成，在生成的初始化阶段开始时就会调用BeanFactoryAware接口的setBeanFactory方法
 * 而生成的BeanPostProcessor接口的bean对象最终会被放到beanPostProcessors集合中 之后每个单例的，懒加载，非抽象的bean对象在初始化的时候都会循环遍历调用该集合中的
 * 所有beanPostProcessor后置器
 * @author Phillip Webb
 * @author Stephane Nicoll
 * @since 2.0.0
 * ErrorPageRegistrarBeanPostProcessor后置处理器允许你以编程方式注册自定义错误页面，为用户提供更友好和个性化的错误信息，
 * 同时保持灵活性和可维护性。这对于构建符合特定需求的Web应用程序非常有用。
 */
public class ErrorPageRegistrarBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {

	private ListableBeanFactory beanFactory;

	private List<ErrorPageRegistrar> registrars;
	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		Assert.isInstanceOf(ListableBeanFactory.class, beanFactory,
				"ErrorPageRegistrarBeanPostProcessor can only be used with a ListableBeanFactory");
		this.beanFactory = (ListableBeanFactory) beanFactory;
	}
	// 再spring refresh()方法中的第9步中 springBoot重定义了onRefresh()方法来创建内嵌的tomcat
	// 而该过程的第一步就是获取ServletWebServerFactory(web容器工厂默认为TomcatServletWebServerFactory:对各组件进行创建初始化操作)bean对象，而该对象初始化的时候
	//会获取所有的beanPostProcessor后置处理器进行调用
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		//注意TomcatServletWebServerFactory是ErrorPageRegistry的子类
		if (bean instanceof ErrorPageRegistry) {
			postProcessBeforeInitialization((ErrorPageRegistry) bean);
		}
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	private void postProcessBeforeInitialization(ErrorPageRegistry registry) {
		//getRegistrars方法是获取所有ErrorPageRegistrar.class的bean对象 而非beanName 我们的DispactherServlet就是再其getBean的时候通过参数注入进行bean对象的生成的
		for (ErrorPageRegistrar registrar : getRegistrars()) {
			registrar.registerErrorPages(registry);
		}
	}

	private Collection<ErrorPageRegistrar> getRegistrars() {
		if (this.registrars == null) {
			// Look up does not include the parent context
			//ErrorPageRegistrar的实现类ErrorPageCustomizer通过工厂方法生成bean对象的时候会进行DispactherServlet bean对象的初始化
			this.registrars = new ArrayList<>(
					this.beanFactory.getBeansOfType(ErrorPageRegistrar.class, false, false).values());
			this.registrars.sort(AnnotationAwareOrderComparator.INSTANCE);
			this.registrars = Collections.unmodifiableList(this.registrars);
		}
		return this.registrars;
	}

}
